package net.hekka.canyoutalk.share.vo;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
 * 모든 값 객체가 상속해야 하는 기본 클래스.
 *
 * @author Jeffrey Ha
 * @since 1.0
 */
public class ValueObject implements Serializable {

    /**
     * 값 객체의 필드명과 값 정보를 문자열로 반환한다.
     *
     * @return 값 객체 정보
     */
    public String toString() {
        StringBuilder builder = new StringBuilder();

        Class thisClass = getClass();
        builder.append(thisClass.getName());
        builder.append(" {");
        builder.append(toString(thisClass));
        builder.append("}");
        return builder.toString();
    }

    /**
     * 해당 클래스의 필드명과 값을 문자열로 반환한다.
     *
     * @param clazz 클래스
     * @return 필드명과 값의 문자열
     */
    private final String toString(Class clazz) {
        StringBuilder builder = new StringBuilder();

        Field[] fields = clazz.getDeclaredFields();
        for (int index = 0; index < fields.length; index++) {
            if (Modifier.isFinal(fields[index].getModifiers())) {
                continue;
            }

            try {
                boolean accessble = fields[index].isAccessible();
                fields[index].setAccessible(true);
                Object value = fields[index].get(this);
                fields[index].setAccessible(accessble);

                builder.append("[");
                builder.append(fields[index].getName());
                builder.append("=");
                builder.append(toString(value));
                builder.append("]");
            } catch (IllegalAccessException e) {
                // SKIP
            }
        }

        Class superClass = clazz.getSuperclass();
        if (!superClass.equals(ValueObject.class)) {
            builder.append(toString(superClass));
        }

        return builder.toString();
    }

    /**
     * 해당 필드의 값을 문자열로 반환한다.
     *
     * @param value 필드
     * @return 값의 문자열
     */
    private final String toString(Object value) {
        if (value == null || !value.getClass().isArray()) {
            return String.valueOf(value);
        }

        StringBuilder builder = new StringBuilder();
        int length = Array.getLength(value);
        for (int index = 0; index < length; index++) {
            builder.append("(");
            builder.append(toString(Array.get(value, index)));
            builder.append(")");
        }

        return builder.toString();
    }
}
